package com.bah.tract.mapping;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.beanutils.BeanUtils;

import com.bah.tract.mapping.PropertyHelper;
import com.bah.tract.model.Task;
import com.bah.tract.model.WorkStore;
import com.bah.tract.service.Property;

public final class TaskFactory {
	private TaskFactory() {

	}

	public static com.bah.tract.model.Task getTask(EntityManager em,
			com.bah.tract.service.Task task) {
		TaskType taskType = TaskType.valueOf(task.getType());
		Class<? extends com.bah.tract.model.Task> taskClass = taskType
				.getTaskClass();
		try {
			// Either make a new task or find one that has been saved
			Query query = em.createQuery(taskType.getQuery());
			for (Property property : task.getIdentifyingProperty()) {
				query.setParameter(property.getName(),
						PropertyHelper.getPropertyValue(property));
			}
			List<?> result = query.getResultList();
			com.bah.tract.model.Task modelTask = null;
			if (result.size() == 0) {
				modelTask = taskClass.newInstance();
				// Figure out the store
				WorkStore store = em.find(WorkStore.class, task.getStoreId());
				if (store == null) {
					throw new IllegalArgumentException(
							"Task references a non-existent store.");
				}
				modelTask.setStore(store);
			} else if (result.size() > 1) {
				throw new IllegalArgumentException(
						"Task not uniquely identified.");
			} else {
				modelTask = (Task) result.get(0);
			}

			@SuppressWarnings("unchecked")
			Map<String, Object> properties = BeanUtils.describe(task);
			// Put the existing properties in a map
			PropertyHelper.processProperties(properties,
					task.getIdentifyingProperty());
			PropertyHelper.processProperties(properties,
					task.getDescriptiveProperty());
			// Copy those properties to the model Task
			BeanUtils.populate(modelTask, properties);
			return modelTask;
		} catch (InstantiationException e) {
			throw new IllegalArgumentException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException(e);
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException(e);
		}
	}
}
